export interface IEventListener {
    callback: Function;
    target?: any;
    isOnce?: boolean;
}

export class BaseEventManager<Key> {
    private _listeners: Map<Key, IEventListener[]> = new Map<Key, IEventListener[]>;

    public on(eventName: Key, callback: Function, target: any = null) {
        this._on(eventName, callback, target, false);
    }

    /**
     * 注册一次性监听，调用后会自动删除这个监听
     * @param eventName 要监听的事件名
     * @param callback 监听回调
     * @param target 调用时需要绑定的目标
     */
    public once(eventName: Key, callback: Function, target: any = null) {
        this._on(eventName, callback, target, true);
    }

    protected _on(eventName: Key, callback: Function, target: any = null, isOnce: boolean) {
        let eventListeners = this._listeners.get(eventName);
        if (!eventListeners) {
            eventListeners = [];
            this._listeners.set(eventName, eventListeners);
        }

        eventListeners.push({
            callback,
            target,
            isOnce
        });
    }

    /**
     * 取消事件监听
     * @param eventName 对应的事件名称
     * @param callback 事件回调，不传则清空对应事件的所有监听
     * @param target 对应的事件绑定对象
     */
    public off(eventName: Key, callback?: Function, target?: any): void {
        if (callback == null) {
            this._listeners.delete(eventName);
            return;
        }

        let eventListeners = this._listeners.get(eventName);
        if (!eventListeners) {
            return;
        }

        this._listeners.set(eventName, eventListeners.filter((listener: IEventListener) => {
            return listener.callback != callback || target != target;
        }));
    }

    /**
     * 派发事件
     * @param eventName 事件名称
     * @param args 事件参数
     */
    public dispatch(eventName: Key, ...args: any): void {
        let eventListeners = this._listeners.get(eventName);
        if (!eventListeners) {
            return;
        }

        for (let index = 0; index < eventListeners.length; index++) {
            let listener: IEventListener = eventListeners[index];
            let callback: Function = listener.callback;
            callback.call(listener.target, ...args);
            if (listener.isOnce) {
                eventListeners.splice(index, 1);
                index--;
            }
        }
    }

    /**
     * 清空事件监听
     */
    public clear() {
        this._listeners.clear();
    }
}

class EventManager extends BaseEventManager<string> {

}

let eventManager = new EventManager();
export { eventManager, EventManager };

export function event_on(eventName: string, callback: Function, target: any = null) {
    eventManager.on(eventName, callback, target);
}

export function event_once(eventName: string, callback: Function, target: any = null) {
    eventManager.once(eventName, callback, target);
}

export function event_off(eventName: string, callback?: Function, target?: any) {
    eventManager.off(eventName, callback, target);
}

export function event_dispatch(eventName: string, ...args: any) {
    eventManager.dispatch(eventName, ...args);
}

export function event_clear() {
    eventManager.clear();
}